<?php

namespace app\shop\library\pay\implements;

use app\admin\model\shop\user\User;
use app\shop\enums\order\OrderPayStatus;
use app\shop\enums\order\OrderStatus;
use app\shop\enums\payment\OrderType;
use app\shop\enums\user\UserMoneyChangeType;
use app\shop\exception\FailException;
use app\shop\library\pay\PayInterface;
use app\shop\library\ShopAuth;
use app\shop\model\order\OrderModel;
use app\shop\model\PaymentTradeModel;
use app\shop\service\LogService;
use app\shop\service\OrderService;
use Exception;
use Throwable;

class BalanceImplement implements PayInterface
{
    private User $userModel;

    public function __construct()
    {
        $this->userModel = new User();
    }

    /**
     * 支付
     * @param array $params
     * @return array
     * @throws FailException
     */
    public function pay(array $params): array
    {
        $model = new OrderModel();
        $order = $model->where('out_trade_no', $params['out_trade_no'])->findOrEmpty();
        if ($order->isEmpty()) {
            throw new FailException('订单不存在或已被删除');
        }

        $user = ShopAuth::instance()->getUser();
        if ($user->isEmpty()) {
            throw new FailException('用户不存在');
        }
        if ($user->money < $order->pay_price) {
            throw new FailException('很抱歉,您的余额不足');
        }

        $user->startTrans();
        try {
            LogService::userMoneyLog($user->id, -abs($order->pay_price), $order->order_no, UserMoneyChangeType::ORDER_PAY);

            $orderService = new OrderService();
            $orderService->afterPay($order->id);

            $user->commit();
        } catch (Throwable $e) {
            $user->rollback();
            throw new FailException('余额付款失败', 0, $e, ['order' => $order->toArray()], true);
        }

        return [
            'status' => 'SUCCESS',
            'order'  => $order->toArray()
        ];
    }

    /**
     * 退款
     * @param array $params
     * @return array
     * @throws Exception
     */
    public function refund(array $params): array
    {
        $model = new OrderModel();
        $order = $model->where('out_trade_no', $params['out_trade_no'])->findOrEmpty();
        if ($order->isEmpty()) {
            throw new Exception('订单不存在或已被删除');
        }

        $user = $this->userModel->where('id', $order->user_id)->findOrEmpty();
        if ($user->isEmpty()) {
            throw new Exception('订单用户信息异常');
        }

        $this->userModel->startTrans();
        try {
            LogService::userMoneyLog($order->user_id, $params['refund_amount'], $order->order_no, UserMoneyChangeType::ORDER_REFUND);

            $this->userModel->commit();
        } catch (Throwable $e) {
            $this->userModel->rollback();
            throw new Exception('余额退款失败：' . $e->getMessage());
        }

        return [
            'status' => 'SUCCESS',
            'order'  => $order->toArray(),
        ];
    }

    /**
     * 交易查询
     * @param array $params
     * @return array
     */
    public function query(array $params): array
    {
        $outTradeNo = $params['out_trade_no'];

        $order = OrderModel::where('out_trade_no', $outTradeNo)->findOrEmpty()->toArray();

        return [
            'status' => $order['status'] === OrderStatus::TO_PAT ? 'FAIL' : 'SUCCESS',
            'result' => $order
        ];
    }

    /**
     * 退款查询
     * @param array $params
     * @return array
     */
    public function queryRefund(array $params): array
    {
        $tradeNo = $params['out_trade_no'];

        $paymentTrade = PaymentTradeModel::where(['trade_no' => $tradeNo, 'order_type' => OrderType::SHOP])->field(['order_id'])->findOrEmpty();
        if ($paymentTrade->isEmpty()) {
            return ['status' => 'FAIL', 'result' => []];
        }
        $order = OrderModel::where('id', $paymentTrade->order_id)->field(['pay_status'])->findOrEmpty();

        return [
            'status' => $order->pay_status == OrderPayStatus::REFUND,
            'result' => $order
        ];
    }

    public function setConfig(array $config): array
    {
        return [];
    }

    public function getPayObject(): static
    {
        return $this;
    }

    public function setNotifyUrl(string $notifyUrl, string $configGroup = 'default'): static
    {
        return $this;
    }

    public function setReturnUrl(string $returnUrl, string $configGroup = 'default'): static
    {
        return $this;
    }
}
